/**
 * @file ChatSessions.cs
 * @author Zane Mayo
 * @date 7/5/2009
 */

using System;
using System.Collections.Generic;

namespace MxitAPI {
	
	/**
	 * Stores information about all the active chat sessions
	 */
	public class ChatSessions {

        public event ChatSessionsEventHandler NewMessagesReceived;
        public event ChatSessionsEventHandler ChatSessionCreated;

		private static log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod().DeclaringType );
		
		private static ChatSessions instance;

        // Holds a list of the chatsessions that must go out with the next newMessagesReceived event
        private List<ChatSession> chatSessionsWithNewMessages;

		Dictionary<int, ChatSession> chatSessions;
		Dictionary<int, int> contactIdToChatSessionId;
		private int currentChatSessionId;
		
		private ChatSessions() {
			chatSessions = new Dictionary<int, ChatSession>();
			contactIdToChatSessionId = new Dictionary<int, int>();
            chatSessionsWithNewMessages = new List<ChatSession>();
			currentChatSessionId = 0;
		}
		
		public static ChatSessions Instance {
			get {
				if ( instance == null )
					instance = new ChatSessions();
				return instance;
			}
		}
		
		/**
		 * Adds a new message to a chat session.
		 * If the chat session does not exist, one is create
		 * @param message The message to add to the chat session
		 */
		public void AddNewMessage( MxitMessage message ){
			int chatSessionId;// = -1;
			
			log.DebugFormat( "Message contact id [{0}]", message.ContactId );
			
			// If the chat session does not exist create a new one and add it to the list of chat sessions.
			// And add it to the dictionary of links between the contactIds and chatSessionIds
            chatSessionId = TryCreateChatSession( Contacts.Instance.GetContact( message.ContactId ) ).ChatSessionId;
			
			//log.DebugFormat( "chatSessions[{0}] [{1}]", chatSessionId, chatSessions );
			
			// Add this message to the chat session
			chatSessions[chatSessionId].AddMessage( message );
            chatSessions[chatSessionId].DoNewMessageRecieved();
            chatSessionsWithNewMessages.Add( chatSessions[ chatSessionId ] );
		}
		
		/**
		 * Adds a new message to chat session
		 * The Information is given by a RawMessage recieved from mxit
		 * @param rawMessage The RawMessage to add to this chat session
		 */
		public void AddNewMessage( RawMessage rawMessage ){
			MxitMessage message = new ReceivedMessage( rawMessage );
			AddNewMessage( message );
		}
		
		/**
		 * Shows whether there are unread messages in any chatSessions.
		 * An unread message is one that hasn't been retrieved with GetNextNewMessage
		 * @return True if there are unread messages
		 */
		public bool NewMessagesExist() {
			foreach ( KeyValuePair<int, ChatSession> kvp in chatSessions ) {
				if ( kvp.Value.NewMessagesExist() ) {
					return true;
				}
			}
			return false;
		}
		
		/**
		 * Returns the next unread message that exists in any chatSession
		 * @return the next unread message from any chat session
		 */
		public MxitMessage GetNextNewMessage() {
			foreach ( KeyValuePair<int, ChatSession> kvp in chatSessions ) {
				if ( kvp.Value.NewMessagesExist() ) {
					return kvp.Value.GetNextNewMessage();
				}
			}
			return null;
		}
		
		/**
		 * Return the next chat session that has unread messages
		 * Does not mark anything as read, so multiple calls can result in the same ChatSession being returned
		 * @return the chat session with unread messages, null if all chat sessions only read messages
		 */
		//Todo maybe this method shouldnt exist
		public ChatSession GetNextChatSessionWithNewMessages() {
			foreach ( KeyValuePair<int, ChatSession> kvp in chatSessions ) {
				if ( kvp.Value.NewMessagesExist() ) {
					return kvp.Value;
				}
			}
			
			return null;
		}

        public ChatSession TryCreateChatSession( Contact contact ) {
            ChatSession chatSession;
            int chatSessionId;

            // If this chat session does not exist already, create it
            if ( !contactIdToChatSessionId.TryGetValue( contact.ContactId, out chatSessionId ) ) {
                chatSession = new ChatSession( currentChatSessionId, contact.ContactId );
                chatSessionId = chatSession.ChatSessionId;
                chatSessions.Add( chatSessionId, chatSession );
                contactIdToChatSessionId.Add( contact.ContactId, chatSessionId );
                log.InfoFormat( "New chat session created. id [{0}]", currentChatSessionId );

                ++currentChatSessionId;


                ChatSessionCreated( this, new AffectedChatSessionsEventArgs( new List<ChatSession> { chatSession } ) ); 
            }
            else
                chatSession = chatSessions[chatSessionId];

            return chatSession;
        }

        public void DoNewMessagesReceived() {
            AffectedChatSessionsEventArgs e = new AffectedChatSessionsEventArgs( chatSessionsWithNewMessages );
            NewMessagesReceived( this, e );

            // Todo can this go before firing the event
            chatSessionsWithNewMessages.Clear();
        }

        /*
        public void DoChatSessionCreated() {
            AffectedChatSessionsEventArgs e = new AffectedChatSessionsEventArgs( ( new List<ChatSession>() ).Add(  ) );
            NewMessagesReceived( this, new AffectedChatSessionsEventArgs( ( new List<ChatSession>() ).Add(  ) ); );

            // Todo can this go before firing the event
            chatSessionsWithNewMessages.Clear();
        }
         */


    }
}
